/** @file libsvm_parser.h
 *
 *  @author Dongryeol Lee (drselee@gmail.com)
 */

#ifndef CORE_DATA_LIBSVM_PARSER_H
#define CORE_DATA_LIBSVM_PARSER_H

#include <boost/mpi.hpp>

#include "core/data/parser_util.h"
#include "core/data/sparse_dataset.h"

namespace core {
namespace data {
class LibSVMParser {
  public:
    static bool Parse(
      boost::mpi::communicator *world,
      const std::string &file_name_in, core::data::SparseDataset *dataset_out,
      int begin_char_in = -1, int count_in = std::numeric_limits<int>::max()) {

      // Open the file.
      std::ifstream stream(file_name_in.c_str());
      if(! stream.is_open()) {
        std::cerr << "Failed to open " << file_name_in << "...\n";
        return false ;
      }

      int num_attributes = 0;
      int failed_line_num;
      int num_points =
        core::data::ParserUtil::CountNumLines(
          stream, -1, begin_char_in, count_in, false,
          &failed_line_num, &num_attributes);

      // Communicate the global number of attributes.
      int local_num_attributes = num_attributes;
      if(world != NULL) {
        boost::mpi::all_reduce(
          * world, local_num_attributes, num_attributes,
          boost::mpi::maximum<int>());
      }

      // Now parse the actual.
      dataset_out->Init(num_attributes, num_points);
      std::cerr << "Detected " << num_attributes << " attributes...\n";
      std::cerr << "Reading in " << num_points << " points...\n";

      // Parse each line.
      std::vector<std::string> parsed_line;
      for(int i = 0; i < num_points; i++) {
        arma::SpCol<double> &column = dataset_out->get_instance(i);

        // Parse the line.
        core::data::ParserUtil::ParseLine(stream, &parsed_line);

        // The first token is the label.
        column[ num_attributes - 1] = atof(parsed_line[0].c_str());

        // The rest constitutes the point.
        for(int j = 1; j < static_cast<int>(parsed_line.size()); j++) {
          int colon_pos = parsed_line[j].find(":");
          int attribute_index =
            atof(parsed_line[j].substr(0, colon_pos).c_str()) - 1;
          column[ attribute_index ] =
            atof(parsed_line[j].c_str() + colon_pos + 1);
        }
      }
      return true;
    }
};
}
}

#endif
